/*
 * BlackLightning.SGESettings
 * Andy Tidball
 * 
 * Project: Black Lightning
 * Copyright: GNU General Public License
 */

using System;
using System.Globalization;
using System.IO;
using System.Text;
using BLLib.Configuration;

namespace BlackLightning {
	/// <summary>
	/// Reads the settings stored on disk by SGE.
	/// </summary>
	internal class SGESettings {
		// constants
		private const string EncryptKey = "ARCEUXWSB"; // the key used to encrypt usernames and passwords

		/// <summary>
		/// Locates Sge.ini as best as possible.
		/// </summary>
		/// <returns>The full path and filename of Sge.ini, or null if it couldn't be found.</returns>
		public static string FindFile() {
			if (File.Exists(Environment.GetEnvironmentVariable("SystemRoot") + Path.DirectorySeparatorChar + "Sge.ini")) {
				return Environment.GetEnvironmentVariable("SystemRoot") + Path.DirectorySeparatorChar + "Sge.ini";
			} else if (File.Exists(Environment.SystemDirectory + Path.DirectorySeparatorChar + "Sge.ini")) {
				return Environment.SystemDirectory + Path.DirectorySeparatorChar + "Sge.ini";
			} else {
				return null;
			}
		}

		// member data
		private string _Username;  // the username stored in the file
		private string _Password;  // the password stored in the file
		private bool   _Remember;  // whether or not the "remember password" box was checked last run
		private string _Game;      // the game name stored in the file
		private string _Character; // the character name stored in the file
		private string _FrontEnd;  // the front end name stored in the file

		/// <summary>
		/// Loads the SGE settings from the given ini file.
		/// </summary>
		/// <param name="Filename">The filename of the SGE ini file to load.</param>
		public SGESettings(string Filename) {
			// load the ini file
			IniFile In = new IniFile(Filename);

			// parse out the stored settings
			Parse(In["Config","Settings"]);
		}

		/// <summary>
		/// The username stored in the file.
		/// </summary>
		public string Username {
			get {
				return _Username;
			}
		}

		/// <summary>
		/// The password stored in the file.
		/// </summary>
		public string Password {
			get {
				return _Password;
			}
		}

		/// <summary>
		/// Whether or not the password was stored last time SGE was run.
		/// </summary>
		public bool RememberPassword {
			get {
				return _Remember;
			}
		}

		/// <summary>
		/// The game name stored in the file.
		/// </summary>
		public string Game {
			get {
				return _Game;
			}
		}

		/// <summary>
		/// The character name stored in the file.
		/// </summary>
		public string Character {
			get {
				return _Character;
			}
		}

		/// <summary>
		/// The front end name stored in the file.
		/// </summary>
		public string FrontEnd {
			get {
				return _FrontEnd;
			}
		}

		/// <summary>
		/// Parses our member data out of the encoded string from the ini file.
		/// </summary>
		/// <param name="Settings">The encoded settings from the ini file.</param>
		private void Parse(string Settings) {
			// parse out the information
			_Username  = ParseString(Settings.Substring(  0, 70), true);
			_Password  = ParseString(Settings.Substring( 70, 70), true);
			_Remember  =            (Settings.Substring(140,  4) == "0100");
			_Game      = ParseString(Settings.Substring(144,130), false);
			_Character = ParseString(Settings.Substring(274,130), false);
			_FrontEnd  = ParseString(Settings.Substring(404, 70), false);
		}

		/// <summary>
		/// Parses a string out of the given encoded settings string.
		/// </summary>
		/// <param name="Settings">The encoded setting string to parse a normal string out of.</param>
		/// <param name="Encrypted">Whether or not the encoded string is also encrypted.</param>
		/// <returns>The string parsed out of the settings.</returns>
		private string ParseString(string Settings, bool Encrypted) {
			// convert the settings string into bytes
			byte[] Bytes = new byte[Settings.Length/2];
			for (int i=0; i<Settings.Length; i+=2) {
				Bytes[i/2] = byte.Parse(Settings[i].ToString() + Settings[i+1].ToString(), NumberStyles.HexNumber);
			}

			// if the bytes are encrypted, run through each and decrypt
			if (Encrypted) {
				int KeyIndex = 0;
				for (int i=0; i<Bytes.Length; ++i) {
					if (Bytes[i] != 0) {
						Bytes[i] = (byte)(Bytes[i] ^ (byte)SGESettings.EncryptKey[KeyIndex]);
						if (Bytes[i] > 128) {
							Bytes[i] -= 128;
						}
					}
					if (KeyIndex >= SGESettings.EncryptKey.Length) {
						KeyIndex = 0;
					} else {
						++KeyIndex;
					}
				}
			}

			// turn the bytes back into a string to return
			StringBuilder Output = new StringBuilder();
			foreach (byte B in Bytes) {
				Output.Append((char)B);
			}

			// trim off anything after the first null character, since SGE writes out null terminated strings
			string OutString = Output.ToString();
			int Index = OutString.IndexOf('\0');
			if (Index >= 0) {
				OutString = OutString.Substring(0, Index);
			}

			// return the string
			return OutString;
		}
	}
}
